package com.zmn.oms.zmn.normal.business.impl.order;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.github.ltsopensource.core.domain.Job;
import com.google.common.collect.Lists;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.common.dro.phenomenon.PhenomenonDRO;
import com.zmn.base.common.data.dubbo.interfaces.phenomenon.PhenomenonListRemoteService;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.base.price.common.dto.fixed.FixedPhenoFilterItemQuery;
import com.zmn.base.price.common.dto.item.ItemCellDRO;
import com.zmn.base.price.common.dto.item.ItemDRO;
import com.zmn.base.price.common.dto.item.ItemQuoteQuery;
import com.zmn.base.price.dubbo.interfaces.calculate.FixedFlowRemoteService;
import com.zmn.base.price.dubbo.interfaces.calculate.ItemPriceRemoteService;
import com.zmn.base.product.common.consts.BaseProductConsts;
import com.zmn.base.product.common.dto.product.erp.ProductGroupDRO;
import com.zmn.base.product.dubbo.interfaces.product.foreign.ProductGroupForeignListRemoteService;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GateTypeConsts;
import com.zmn.consts.GlobalConsts;
import com.zmn.erp.common.newbiz.constant.MqConstant;
import com.zmn.erp.common.newbiz.dio.SettlePartAccountDIO;
import com.zmn.erp.common.newbiz.dio.part.EngPartAmountDIO;
import com.zmn.erp.common.newbiz.dio.part.OutSourcingPartAuditDIO;
import com.zmn.log.client.user.operation.AddUserOperationLogRequest;
import com.zmn.log.client.user.operation.UserOperationLogClient;
import com.zmn.log.client.user.operation.enums.UserType;
import com.zmn.log.client.user.operation.item.DeviceLogItem;
import com.zmn.log.client.user.operation.item.EntryLogItem;
import com.zmn.log.client.user.operation.item.UserLogItem;
import com.zmn.log.client.user.operation.item.event.AddOrderEventLogItem;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.impl.order.OrderBaseBServiceImpl;
import com.zmn.oms.business.interfaces.base.BaseCodeService;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.business.interfaces.order.DuplicateOrderBService;
import com.zmn.oms.business.interfaces.orderamount.OrderAmountCalcBService;
import com.zmn.oms.business.interfaces.orderfinalpricequotation.OrderFinalPriceQuotationBService;
import com.zmn.oms.business.interfaces.orderstock.OrderStockBService;
import com.zmn.oms.business.interfaces.part.OrderPartBService;
import com.zmn.oms.common.annotation.ZsNormalOrderWorkLog;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dio.finalpricequotation.OrderFinalPriceQuotationDataDIO;
import com.zmn.oms.common.dio.normal.master.UpdateAddressDIO;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.exception.chan.ChannelFacadeException;
import com.zmn.oms.common.utils.MathUtil;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.manager.utils.OmsMqTagConsts;
import com.zmn.oms.manager.utils.TaskConsts;
import com.zmn.oms.model.bo.order.OrderBO;
import com.zmn.oms.model.bo.orderamount.CalcAddOrderAmountDIO;
import com.zmn.oms.model.bo.orderamount.DiscountConditionParamsDIO;
import com.zmn.oms.model.bo.orderamount.OrderAmountCalcBO;
import com.zmn.oms.model.bo.orderamount.OrderAmountDIO;
import com.zmn.oms.model.dto.changerecord.ChangeLiableMasterDTO;
import com.zmn.oms.model.dto.order.NewOrderDistributeMasterDTO;
import com.zmn.oms.model.dto.order.NewOrderExternalShopDTO;
import com.zmn.oms.model.dto.order.OrderDTO;
import com.zmn.oms.model.dto.order.OrderReworkDTO;
import com.zmn.oms.model.dto.order.zmn.FinalPriceNewOrderExtDTO;
import com.zmn.oms.model.dto.order.zmn.ZsNormalAddressOrderDTO;
import com.zmn.oms.model.dto.order.zmn.ZsNormalNewOrderDTO;
import com.zmn.oms.model.dto.order.zmn.ZsNormalUpdateOrderDTO;
import com.zmn.oms.model.dto.orderstock.LockStockDTO;
import com.zmn.oms.model.dto.orderstock.ReleaseStockDTO;
import com.zmn.oms.model.dto.part.PartPricePostDTO;
import com.zmn.oms.model.dto.product.NewOrderAdvanceQuoteDTO;
import com.zmn.oms.model.dto.product.OrderProductDTO;
import com.zmn.oms.model.dto.serviceitem.AddOrderServiceItemDTO;
import com.zmn.oms.model.dto.work.modify.CheckReworkOrderDTO;
import com.zmn.oms.model.dto.work.modify.ProductTaraiffIdDTO;
import com.zmn.oms.model.dto.work.modify.must.OrderAssignBackDTO;
import com.zmn.oms.model.dto.work.modify.must.OrderDistributeBackDTO;
import com.zmn.oms.model.dto.work.modify.other.ZsPartReimburseDTO;
import com.zmn.oms.model.dto.work.modify.other.ZsPartReimburseGroupDTO;
import com.zmn.oms.model.dto.work.modify.other.ZsRemarkDTO;
import com.zmn.oms.model.entity.activity.OrderActivity;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.distribute.OrderPreDistributeRecord;
import com.zmn.oms.model.entity.masterworking.MasterWorking;
import com.zmn.oms.model.entity.operation.OrderOperation;
import com.zmn.oms.model.entity.order.Order;
import com.zmn.oms.model.entity.order.OrderExtend;
import com.zmn.oms.model.entity.order.OrderFinalPrice;
import com.zmn.oms.model.entity.orderfinalpricequotation.OrderFinalPriceQuotation;
import com.zmn.oms.model.entity.part.OrderPart;
import com.zmn.oms.model.entity.post.OrderPost;
import com.zmn.oms.model.entity.product.OrderProduct;
import com.zmn.oms.model.entity.product.OrderProductExtend;
import com.zmn.oms.model.entity.quotation3.OrderFaultPhenomenon;
import com.zmn.oms.model.entity.serviceitem.OrderServiceItem;
import com.zmn.oms.model.entity.shop.OrderExternalShop;
import com.zmn.oms.model.entity.serviceitem.OrderServiceItemCell;
import com.zmn.oms.model.entity.shop.OrderShop;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.mongo.distribute.PlaceAnOrderPreDistribute;
import com.zmn.oms.model.vo.work.DistributeVO;
import com.zmn.oms.services.interfaces.changerecord.OrderChangeRecordService;
import com.zmn.oms.services.interfaces.distribute.PreDistributeRecordService;
import com.zmn.oms.services.interfaces.express.OrderPostService;
import com.zmn.oms.services.interfaces.order.OrderFinalPriceService;
import com.zmn.oms.services.interfaces.orderfinalpricequotation.OrderFinalPriceQuotationService;
import com.zmn.oms.services.interfaces.part.OrderPartService;
import com.zmn.oms.services.interfaces.shop.OrderExternalShopService;
import com.zmn.oms.services.interfaces.quotation3.OrderFaultPhenomenonService;
import com.zmn.oms.services.interfaces.tag.OrderTagService;
import com.zmn.oms.third.jingdong.JingdongConsts;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeOrderClueDetailBService;
import com.zmn.oms.zmn.business.interfaces.grab.NonGridGrabOrderBService;
import com.zmn.oms.zmn.business.interfaces.order.ZsOrderBService;
import com.zmn.oms.zmn.business.interfaces.work.OrderWorkAssignBackBService;
import com.zmn.oms.zmn.business.interfaces.work.OrderWorkDistributeBackBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.oms.zmn.business.interfaces.work.customwork.ZsDistributeWorkBService;
import com.zmn.oms.zmn.normal.business.interfaces.order.ZsNormalOrderBService;
import com.zmn.oms.zmn.normal.business.interfaces.order.advancequote.AdvanceQuoteModifyBService;
import com.zmn.oms.zmn.normal.business.interfaces.serviceitem.ZsNormalOrderServiceItemBService;
import com.zmn.saas.dubbo.constant.SaasDubboConsts;
import com.zmn.saas.dubbo.dto.shop.ShopDIO;
import com.zmn.saas.dubbo.dto.shop.ShopDRO;
import com.zmn.saas.dubbo.interfaces.shop.ShopRemoteService;
import com.zmn.scm2.common.model.dio.scm.reimburse.ScmReimburseResultDIO;
import com.zmn.scm2.common.model.dio.scm.reimburse.item.ScmReimburseItemCostDIO;
import com.zmn.scm2.common.model.dio.scm.reimburse.item.ScmReimburseItemPartDIO;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkModifyRemoteService;
import com.zmn.uuc.common.constant.DubboConsts;
import com.zmn.uuc.dubbo.interfaces.user.UserModifyRemoteService;
import eu.bitwalker.useragentutils.UserAgent;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：普通单操作
 *
 * @author liuying
 * @date 2019/01/14 23:03
 */
@Service
public class ZsNormalOrderBServiceImpl extends OrderBaseBServiceImpl implements ZsNormalOrderBService {

    @Autowired
    private OrderPartBService orderPartBService;
    @Autowired
    private ZsOrderBService zsOrderBService;
    @Autowired
    private BaseCodeService baseCodeService;
    @Autowired
    private OrderPartService orderPartService;
    @Autowired
    private WorkFlowContextBService workFlowContextBService;
    @Autowired
    private OrderWorkDistributeBackBService orderWorkDistributeBackBService;
    @Autowired
    private OrderWorkAssignBackBService orderWorkAssignBackBService;
    @Autowired
    private OrderAmountCalcBService orderAmountCalcBService;
    @Autowired
    private FacadeOrderClueDetailBService facadeOrderClueDetailBService;
    @Autowired
    private ZsNormalOrderBService zsNormalOrderBService;
    @Autowired
    private OrderWorkEsBService orderWorkEsBService;

    @Autowired
    TaskManager taskManager;
    @Autowired
    DefaultKeyGenerator defaultKeyGenerator;
    @Autowired
    OrderPostService orderPostService;
    @Resource
    ZmnMQSender zmnMQSender;
    @Resource
    private RedisManager redisManager;
    @Resource
    private UserOperationLogClient logClient;
    @Autowired
    private OrderStockBService orderStockBService;
    @Autowired
    private ZsDistributeWorkBService zsDistributeWorkBService;
    @Autowired
    private PreDistributeRecordService preDistributeRecordService;
    @Autowired
    private OrderChangeRecordService orderChangeRecordService;
    @Autowired
    private OrderFinalPriceService orderFinalPriceService;
    @Autowired
    private OrderTagService orderTagService;
    @Autowired
    private NonGridGrabOrderBService nonGridGrabOrderBService;
    @Autowired
    private DuplicateOrderBService duplicateOrderBService;
    @Autowired
    private OrderExternalShopService orderExternalShopService;
    @Autowired
    private OrderFinalPriceQuotationService orderFinalPriceQuotationService;
    @Autowired
    private OrderFaultPhenomenonService orderFaultPhenomenonService;
    @Autowired
    private OrderFinalPriceQuotationBService orderFinalPriceQuotationBService;
    @Autowired
    private AdvanceQuoteModifyBService advanceQuoteModifyBService;

    @DubboReference(version = SaasDubboConsts.INTERFACE_VERSION, check = false)
    private ShopRemoteService shopRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private UserModifyRemoteService userModifyRemoteService;
    @DubboReference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    private ProductGroupForeignListRemoteService productGroupForeignListRemoteService;

    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkModifyRemoteService trackWorkModifyRemoteService;

    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private PhenomenonListRemoteService phenomenonListRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private FixedFlowRemoteService fixedFlowRemoteService;

    /**
     * 自动标记测试号码
     */
    @NacosValue(value = "${order.auto.mark.test.telephone:0}", autoRefreshed = true)
    protected List<String> ORDER_AUTO_MARK_TEST_TELEPHONE;

    public ZsNormalOrderBServiceImpl() {
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public OrderReworkDTO checkReworkId(CheckReworkOrderDTO checkReworkOrderDTO) throws OmsBaseException {
        return super.checkReworkId(checkReworkOrderDTO);
    }

    @Override
    public void saveSysPartReimburse(Long orderId, Long workId, List<OrderPart> partList) throws OmsBaseException {
        logger.info("ZsNormalOrderBServiceImpl#saveSysPartReimburse 系统自动报销，保存配件 入参：{}", JSON.toJSONString(partList));
        ZsPartReimburseGroupDTO zsPartReimburseGroupDTO = new ZsPartReimburseGroupDTO();

        zsPartReimburseGroupDTO.setOrderId(orderId);
        zsPartReimburseGroupDTO.setWorkId(workId);
        zsPartReimburseGroupDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        zsPartReimburseGroupDTO.setOperatorId(1L);
        zsPartReimburseGroupDTO.setOperator("系统");
        zsPartReimburseGroupDTO.setSysPartReimburse(GlobalConsts.YES);

        // 分组
        Map<String, List<OrderPart>> reimburseGroup = partList.stream()
                .filter(part -> Objects.equals(GlobalConsts.YES, part.getReimburse()))
                .collect(Collectors.groupingBy(OrderPart::getReimburseId));

        List<ZsPartReimburseDTO> partReimburseList = Lists.newArrayList();
        reimburseGroup.forEach((applyId, orderPartList) -> {
            /* 每组中所有配件 */
            List<PartPricePostDTO> partPricePostList = orderPartList.stream().map(orderPart -> {
                PartPricePostDTO partPricePostDTO = BeanMapper.map(orderPart, PartPricePostDTO.class);
                partPricePostDTO.setApplyId(orderPart.getReimburseId());
                partPricePostDTO.setDeclare(orderPart.getDeclarePrice());
                return partPricePostDTO;
            }).collect(Collectors.toList());

            ZsPartReimburseDTO partReimburse = new ZsPartReimburseDTO();
            partReimburse.setApplyId(applyId);
            partReimburse.setPartPricePostDTO(partPricePostList);
            partReimburse.setStatus(OrderConsts.PART_REIMBURSE_STATUS_NO);
            partReimburseList.add(partReimburse);
        });
        zsPartReimburseGroupDTO.setZsPartReimburseList(partReimburseList);
        logger.info("系统自动报销，保存配件列表：{}", JSON.toJSONString(zsPartReimburseGroupDTO));
        zsNormalOrderBService.savePartReimburse(zsPartReimburseGroupDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_PART_REIMBURSE)
    public void savePartReimburse(ZsPartReimburseGroupDTO zsPartReimburseGroupDTO) throws OmsBaseException {
        // 外报配件金额
        int report = 0;

        // 订单杂项费用
        int transport = 0;

        // 配件报销金额
        Integer partReimburseAmount = 0;

        // 工单的配件报销状态
        int orderReimburseStatus;

        // 【配件报销】每组配件的审核状态
        List<Integer> reimburseStatusList = Lists.newArrayList();

        // 修改报销金额 供应链
        List<ScmReimburseResultDIO> scmReimburseResultList = Lists.newArrayList();

        // 根据订单Id查询出配件总金额作为报销金额
        List<OrderPart> orderParts = orderPartBService.listPartReimburseByOrderId(zsPartReimburseGroupDTO.getOrderId());

        /* 遍历每组报销单 */
        for (ZsPartReimburseDTO zsPartReimburseDTO : zsPartReimburseGroupDTO.getZsPartReimburseList()) {

            // 订单配件报销状态
            int reimburseStatus = zsPartReimburseDTO.getStatus();

            partReimburseAmount += zsPartReimburseDTO.getPartPricePostDTO().stream().mapToInt(part ->
                    MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber())).sum();

            // 报销成功
            if (Objects.equals(reimburseStatus, OrderConsts.PART_REIMBURSE_STATUS_SUCCESS)) {
                List<PartPricePostDTO> partPriceList = zsPartReimburseDTO.getPartPricePostDTO();

                // 修改单价
                zsPartReimburseDTO.setOrderId(zsPartReimburseGroupDTO.getOrderId());
                orderPartService.updateOrderPartPriceByOrderId(zsPartReimburseDTO);

                // 临时map，为OrderPart setPrice用
                Map<Long, PartPricePostDTO> tempMap = partPriceList.stream()
                        .collect(Collectors.toMap(PartPricePostDTO::getOrderPartId, orderPart -> orderPart, (t, t2) -> t));

                // 过滤出报销单号为当前报销单号的
                List<OrderPart> orderPartList = orderParts.stream()
                        .filter(orderPart -> Objects.equals(orderPart.getReimburseId(), zsPartReimburseDTO.getApplyId()))
                        .collect(Collectors.toList());

                // 总报销金额（包含【外报 和 运杂费】）
                int totalReimburseAmount = 0;

                ScmReimburseResultDIO reimburseResultDIO = new ScmReimburseResultDIO();
                reimburseResultDIO.setReimburseId(zsPartReimburseDTO.getApplyId());
                reimburseResultDIO.setResult(GlobalConsts.YES);
                reimburseResultDIO.setType(orderPartList.get(0).getPartType());

                if (Objects.equals(reimburseResultDIO.getType(), OrderConsts.PART_TYPE_SOURCING_OUT)) {
                    /* 外报 */
                    List<ScmReimburseItemPartDIO> scmReimburseItemPartDIOS = new ArrayList<>();

                    /* 遍历每组报销单的每个配件 */
                    for (OrderPart orderPart : orderPartList) {
                        // 根据页面提交的数据重新赋值
                        PartPricePostDTO partPricePostDTO = tempMap.get(orderPart.getOrderPartId());

                        if (partPricePostDTO != null) {
                            orderPart.setPrice(partPricePostDTO.getPrice());
                        }

                        ScmReimburseItemPartDIO partDIO = new ScmReimburseItemPartDIO();
                        partDIO.setReimburseAmount(orderPart.getPrice());
                        partDIO.setItemId(Integer.valueOf(orderPart.getDrawId()));
                        scmReimburseItemPartDIOS.add(partDIO);

                        // 外报销售额
                        report += MathUtil.amountMultiplyNumber(orderPart.getPrice(), orderPart.getNumber());
                        totalReimburseAmount += MathUtil.amountMultiplyNumber(orderPart.getPrice(), orderPart.getNumber());
                    }
                    reimburseResultDIO.setScmReimburseItemPartDIOList(scmReimburseItemPartDIOS);
                } else if (Objects.equals(reimburseResultDIO.getType(), OrderConsts.PART_TYPE_DELIVER)) {
                    /* 订单杂项费用 */

                    // 根据页面提交的数据重新赋值
                    PartPricePostDTO partPricePostDTO = tempMap.get(orderPartList.get(0).getOrderPartId());
                    if (partPricePostDTO != null) {
                        orderPartList.get(0).setPrice(partPricePostDTO.getPrice());
                    }

                    ScmReimburseItemCostDIO dio = new ScmReimburseItemCostDIO();
                    dio.setItemId(Integer.valueOf(orderPartList.get(0).getDrawId()));
                    dio.setReimburseAmount(orderPartList.get(0).getPrice());
                    reimburseResultDIO.setScmReimburseItemCostDIO(dio);
                    totalReimburseAmount += MathUtil.amountMultiplyNumber(orderPartList.get(0).getPrice(),
                            orderPartList.get(0).getNumber());
                    // 运杂销售额
                    transport += MathUtil.amountMultiplyNumber(orderPartList.get(0).getPrice(),
                            orderPartList.get(0).getNumber());
                } else {
                    throw new OmsBaseException("配件报销异常，有配件类型不是外报和运杂");
                }

                reimburseResultDIO.setReimburseAmount(totalReimburseAmount);
                scmReimburseResultList.add(reimburseResultDIO);

            } else if (Objects.equals(reimburseStatus, OrderConsts.PART_REIMBURSE_STATUS_FAIL)
                    || Objects.equals(reimburseStatus, OrderConsts.PART_REIMBURSE_STATUS_NO)) {
                // 报销失败 或 不予报销
                List<OrderPart> orderPartList = orderParts.stream()
                        .filter(orderPart -> Objects.equals(orderPart.getReimburseId(), zsPartReimburseDTO.getApplyId()))
                        .collect(Collectors.toList());

                orderPartList.forEach((orderPart) -> {
                    ScmReimburseResultDIO reimburseResultDIO = new ScmReimburseResultDIO();
                    reimburseResultDIO.setReimburseId(zsPartReimburseDTO.getApplyId());
                    reimburseResultDIO.setResult(GlobalConsts.NO);
                    scmReimburseResultList.add(reimburseResultDIO);
                });
            } else {
                throw new OmsBaseException("报销状态异常：" + reimburseStatus);
            }

            reimburseStatusList.add(reimburseStatus);
            // 更新【报销单】中所有【配件】的报销状态
            orderPartService.updateReimburseStatusByReimburseId(zsPartReimburseGroupDTO.getOrderId(), zsPartReimburseDTO.getApplyId(), reimburseStatus);
        }

        List<OrderPart> allOrderPartList = orderPartService.listByOrderIdSrcMaster(zsPartReimburseGroupDTO.getOrderId());
        // 根据订单Id查询订单用到的配件
        boolean noneSettSubjectType = allOrderPartList.stream().anyMatch(e -> NumberUtil.isNullOrZero(e.getSettlementSubjectType()));
        if (noneSettSubjectType) {
            throw new OmsBaseException("配件无结算主体");
        }

        // 同步库存中单价金额
        String key = StringUtil.getRandomsString(32);
        logger.info("#sync#scm2#reimburse#result#sendMq key : {},message:{}", key, JSON.toJSONString(scmReimburseResultList));
        zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_SCM2, OmsMqTagConsts.SCM_REIMBURSE_RESULT_MQ_TAGS, key, JSON.toJSONString(scmReimburseResultList));

        // 报销成功 重新计算配件总金额以及各配件金额
        Integer partAmount = 0;
        Integer inSourcingAmount = 0;
        Integer outSourcingAmount = 0;
        Integer deliverAmount = 0;
        for (OrderPart orderPart : allOrderPartList) {
            partAmount += MathUtil.amountMultiplyNumber(orderPart.getPrice(), orderPart.getNumber());
            switch (orderPart.getPartType()) {
                case OrderConsts.PART_TYPE_SOURCING_IN:
                    inSourcingAmount += MathUtil.amountMultiplyNumber(orderPart.getPrice(), orderPart.getNumber());
                    break;
                case OrderConsts.PART_TYPE_SOURCING_OUT:
                    outSourcingAmount += MathUtil.amountMultiplyNumber(orderPart.getPrice(), orderPart.getNumber());
                    break;
                case OrderConsts.PART_TYPE_DELIVER:
                    deliverAmount += MathUtil.amountMultiplyNumber(orderPart.getPrice(), orderPart.getNumber());
                    break;
                case OrderConsts.PART_TYPE_FACTORY:
                    break;
                default:
                    break;
            }
        }

        /*
            工单的配件报销状态生成规则：
                所有组中，有一组报销成功，工单的【配件报销状态】就设置为成功.
                有一个失败就失败，既有【失败】又有【不予报销】，则失败.
                只有【不予报销】就设置不予报销.
        */
        if (reimburseStatusList.contains(OrderConsts.PART_REIMBURSE_STATUS_SUCCESS)) {
            orderReimburseStatus = OrderConsts.PART_REIMBURSE_STATUS_SUCCESS;
        } else if (reimburseStatusList.contains(OrderConsts.PART_REIMBURSE_STATUS_FAIL)) {
            orderReimburseStatus = OrderConsts.PART_REIMBURSE_STATUS_FAIL;
        } else {
            // 不予报销
            orderReimburseStatus = OrderConsts.PART_REIMBURSE_STATUS_NO;
        }

        // 设置报销时间
        // 设置配件报销标识 不报销
        OrderWork orderWork = new OrderWork();
        orderWork.setWorkId(zsPartReimburseGroupDTO.getWorkId());
        orderWork.setOrderId(zsPartReimburseGroupDTO.getOrderId());
        orderWork.setPartReimburse(GlobalConsts.NO);
        orderWork.setPartReimburseTime(DateUtil.getNow());
        orderWork.setPartReimburseAmount(partReimburseAmount);
        orderWork.setPartReimburseStatus(orderReimburseStatus);
        orderWork.setCurrentRemark(zsPartReimburseGroupDTO.getOperatorRemark());

        if (report > 0) {
            orderWork.setOutSourcingAmount(report);
        }

        if (transport > 0) {
            orderWork.setDeliverAmount(transport);
        }

        orderWork.setPartAmount(partAmount);
        orderWork.setInSourcingAmount(inSourcingAmount);
        orderWork.setOutSourcingAmount(outSourcingAmount);
        orderWork.setDeliverAmount(deliverAmount);

        orderWorkService.updatePartReimburse(orderWork);

        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKey(zsPartReimburseGroupDTO.getOrderId(), zsPartReimburseGroupDTO.getWorkId());
        // 将【内采配件】 或者 报销类型为：【报销成功】的配件 发送给ERP
        List<OrderPart> orderPartList = allOrderPartList.stream().filter(e ->
                Objects.equals(e.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN)
                        || Objects.equals(e.getReimburseStatus(), OrderConsts.PART_REIMBURSE_STATUS_SUCCESS))
                .collect(Collectors.toList());
        logger.info("工单：{} 发送到ERP的配件信息：{}", zsPartReimburseGroupDTO.getOrderId(), JSON.toJSONString(orderPartList));
        if (CollectionUtils.isNotEmpty(orderPartList)) {
            this.sendPartReimburseInfoToERP(dbOrderWork, orderWork, zsPartReimburseGroupDTO, orderPartList);
        }
    }

    /**
     * 报销成功时发送相关信息给ERP
     *
     * @param orderWork
     * @param partReimburseDTO
     * @param orderParts
     */
    @Override
    public void sendPartReimburseInfoToERP(OrderWork dbOrderWork, OrderWork orderWork, ZsPartReimburseGroupDTO partReimburseDTO, List<OrderPart> orderParts) {
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(partReimburseDTO.getOrderId());

        OutSourcingPartAuditDIO partAuditDIO = new OutSourcingPartAuditDIO();
        partAuditDIO.setOrderId(dbOrderWork.getOrderId());
        partAuditDIO.setWorkId(dbOrderWork.getWorkId());
        partAuditDIO.setPlat(dbOrderWork.getPlatWork());
        partAuditDIO.setBizType(dbOrderWork.getBizType());
        partAuditDIO.setSpCompanyId(dbOrderWork.getManageCompanyId());
        partAuditDIO.setSpCompanyName(dbOrderWork.getManageCompanyName());
        partAuditDIO.setSpCompanyType(dbOrderWork.getManageCompanyType());
        partAuditDIO.setAuditor(partReimburseDTO.getOperator());
        partAuditDIO.setOrderType(dbOrderWork.getType());

        // 计算总配件金额：是【内采】但支付类型不是【质保金】 or 配件类型是【外报 或 订单杂项费用】
        Integer partAmount = orderParts.stream().filter(part -> {
            return (Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && !Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY))
                    || Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_OUT) || Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_DELIVER);
        }).mapToInt(part -> {
            return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
        }).sum();
        partAuditDIO.setPartAmount(partAmount);

        // 计算内采总金额：配件类型是【内采】但支付类型不是【质保金】
        Integer cashInSourcingPartAmount = orderParts.stream().filter(part -> {
            return Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && !Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY);
        }).mapToInt(part -> {
            return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
        }).sum();

        partAuditDIO.setDepositInsourcingPartAmount(Optional.ofNullable(orderWork.getInSourcingAmount()).orElse(0) - Optional.ofNullable(cashInSourcingPartAmount).orElse(0));

        // 订单收费=订单金额-优惠
        partAuditDIO.setOrderAmount(Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0));
        partAuditDIO.setOrderReceiveAmount(Optional.ofNullable(dbOrderWork.getTotalAmount()).orElse(0));

        // 内部价：我们自己的定价l
        List<OrderServiceItem> orderServiceItemList = orderServiceItemService.listByOrderId(orderWork.getOrderId());
        int internalSettlementPrice = orderServiceItemList.stream()
                .filter(e -> e.getInternalTotalPrice() != null)
                .mapToInt(OrderServiceItem::getInternalTotalPrice).sum();
        partAuditDIO.setInternalStatementAmount(internalSettlementPrice);

        partAuditDIO.setSummary(orderDetail.getProductInfo());

        // 配件按工程师统计信息
        List<EngPartAmountDIO> partAmountDIOList = Lists.newArrayList();
        Map<Integer, List<OrderPart>> orderPartMap = orderParts.stream().collect(Collectors.groupingBy(OrderPart::getMasterId));
        orderPartMap.forEach((masterId, orderPartList) -> {
            EngPartAmountDIO partAmountDIO = new EngPartAmountDIO();

            partAmountDIO.setEngineerId(masterId);
            partAmountDIO.setEngineerName(orderPartList.get(0).getMasterName());

            // 现金内采配件结算主体
            List<SettlePartAccountDIO> cashInsourcingPartAmountList = orderPartList.stream().filter(part -> {
                return Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && !Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY);
            }).map(part -> {
                SettlePartAccountDIO dio = new SettlePartAccountDIO();
                dio.setPartAmount(MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber()));
                dio.setSettlementSubjectType(part.getSettlementSubjectType());
                dio.setPartsReimburseStatus(part.getReimburseStatus());
                return dio;
            }).collect(Collectors.toList());
            partAmountDIO.setCashInsourcingPartAmountList(cashInsourcingPartAmountList);

            // 外报配件结算主体
            List<SettlePartAccountDIO> outsourcingPartAmountList = orderPartList.stream().filter(part -> {
                return Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_OUT);
            }).map(part -> {
                SettlePartAccountDIO dio = new SettlePartAccountDIO();
                dio.setPartAmount(MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber()));
                dio.setSettlementSubjectType(part.getSettlementSubjectType());
                dio.setPartsReimburseStatus(part.getReimburseStatus());
                return dio;
            }).collect(Collectors.toList());
            partAmountDIO.setOutsourcingPartAmountList(outsourcingPartAmountList);

            // 运杂结算主体
            List<SettlePartAccountDIO> deliverPartAmountList = orderPartList.stream()
                    .filter(part -> Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_DELIVER))
                    .map(part -> {
                        SettlePartAccountDIO dio = new SettlePartAccountDIO();
                        dio.setPartAmount(MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber()));
                        dio.setSettlementSubjectType(part.getSettlementSubjectType());
                        dio.setPartsReimburseStatus(part.getReimburseStatus());
                        return dio;
                    }).collect(Collectors.toList());
            partAmountDIO.setOtherPartAmountList(deliverPartAmountList);

            partAmountDIOList.add(partAmountDIO);
        });
        partAuditDIO.setEngPartAmountList(partAmountDIOList);

        String key = String.format("%s-%s", orderWork.getOrderId(), DateUtil.getNowTimestamp());
        String content = JSON.toJSONString(partAuditDIO);
        logger.info("发送配件报销信息 key:{}, content:{}", key, content);
        zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_ERP, MqConstant.OUT_SOUCRCING_PART_AUDIT_TAG, key, content);
    }

    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_REMARK)
    public void saveWorkRemark(ZsRemarkDTO dto) {
        String remark = StringUtils.defaultString(dto.getRemark());
        String masterRemark = StringUtils.defaultString(dto.getMasterRemark());
        OrderWork orderWork = new OrderWork();
        orderWork.setUpdater(dto.getOperator());
        orderWork.setOrderId(dto.getOrderId());
        orderWork.setWorkId(dto.getWorkId());
        orderWork.setCurrentRemark(remark);
        orderWork.setMasterRemark(masterRemark);
        orderWorkService.updateWorkRemark(orderWork);
    }

    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_FACTORY_REMARK)
    public void saveFactoryRemark(ZsRemarkDTO dto) {
    }

    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_PLAT_MASTER_REMARK)
    public void saveMasterRemark(ZsRemarkDTO dto) {
    }

    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_SERVICE_PROVIDER_REMARK)
    public void saveServiceProviderRemark(ZsRemarkDTO dto) {
    }

    @Override
    public void saveConfirmOrder(ZsNormalUpdateOrderDTO zsNormalUpdateOrderDTO) throws OmsBaseException {
        if (CollectionUtils.isEmpty(zsNormalUpdateOrderDTO.getOrderProductList())) {
            throw new OmsBaseException("订单不能为空");
        }

        // 订单确认
        zsNormalUpdateOrderDTO.setStatus(OrderStatusConsts.WORK_STATUS_CONFIRM);

        // 获取修改数据
        OrderDTO orderDTO = super.getUpdateOrderDTO(zsNormalUpdateOrderDTO);

        // 修改
        zsOrderBService.confirmOrder(orderDTO);

        // 如果有预分配服务公司id，则存入redis
        if (NumberUtil.isNotNullOrZero(zsNormalUpdateOrderDTO.getPreManageCompanyId())){
            String redisKey = String.format(RedisKeyConsts.CHECK_MANAGE_COMPANY_KEY, zsNormalUpdateOrderDTO.getWorkId());
            String value = zsNormalUpdateOrderDTO.getPreManageCompanyId() + "-" + zsNormalUpdateOrderDTO.getPreManageCompanyName();
            redisManager.setex(redisKey, value, 7 * 24 * 60 * 60);
        }

        try {
            // 处理提前报价相关问题
            advanceQuoteModifyBService.processUpdateAdvanceQuote(orderDTO);
        } catch (Exception e) {
            logger.error("同步保存报价信息失败", e);
        }

        // 工单自动流转
        workFlowContextBService.asyncAutoFlowDelayMillis(orderDTO.getOrderId(), orderDTO.getWorkId(), 1500);
        //workFlowContextBService.asyncAutoFlow(orderDTO.getOrderId(),orderDTO.getWorkId());
    }

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public void updateOrder(ZsNormalUpdateOrderDTO zsNormalUpdateOrderDTO) throws OmsBaseException {
        logger.info("[{}]修改订单DTO：【{}】", zsNormalUpdateOrderDTO.getOrderId(), JSON.toJSONString(zsNormalUpdateOrderDTO));
        if (CollectionUtils.isEmpty(zsNormalUpdateOrderDTO.getOrderProductList())) {
            throw new OmsBaseException("订单不能为空");
        }

        // 获取修改数据
        OrderDTO orderDTO = super.getUpdateOrderDTO(zsNormalUpdateOrderDTO);

        // 判断无网格抢单

        // 更新
        OrderBO orderBO = zsOrderBService.updateOrder(orderDTO);

        // 分单撤回
        if (orderBO.getAssignBack() != null && orderBO.getAssignBack().isStatusBool() && zsNormalUpdateOrderDTO.isVerifyAssignBack()) {
            OrderAssignBackDTO orderAssignBackDTO = new OrderAssignBackDTO();
            orderAssignBackDTO.setWorkId(orderDTO.getWorkId());
            orderAssignBackDTO.setOrderId(orderDTO.getOrderId());
            orderAssignBackDTO.setStatus(OrderStatusConsts.WORK_STATUS_CONFIRM);
            orderAssignBackDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            orderAssignBackDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            orderAssignBackDTO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
            orderAssignBackDTO.setOperatorRemark("修改订单，自动撤回，原因：" + orderBO.getAssignBack().getData());
            logger.info("[{}]修改订单-自动撤回原因==>[{}]", orderDTO.getWorkId(), orderBO.getAssignBack().getData());
            orderWorkAssignBackBService.saveAssignBack(orderAssignBackDTO);

            // 工单自动流转
            OrderWork orderWork = orderBO.getOrderWork();
            workFlowContextBService.asyncAutoFlow(orderWork.getOrderId(),orderWork.getWorkId());
            return;
        }

        // 常规派单撤回判断
        /*boolean normalDistributeBack = (orderBO.getDistributeBack() != null
                && orderBO.getDistributeBack().isStatusBool()
                && zsNormalUpdateOrderDTO.isVerifyDistributeBack());
        // 总公司员工平台直派撤回判断
        boolean headquartersDistributeBack = !zsNormalUpdateOrderDTO.isBranchCompany() && Objects.equals(orderDTO.getOrderWork().getDistributeWay(), OrderDistributeConsts.DISTRIBUTE_WAY_PLAT)
                && !Objects.equals(orderDTO.getDbOrderDetail().getGridCompanyId(), orderDTO.getOrderDetail().getGridCompanyId()) && orderDTO.getDbOrderWork().getStatus() >= OrderStatusConsts.WORK_STATUS_DISTRIBUTE;
        logger.info("总公司员工[{}]-派单路径[{}]-修改前行政子公司[{}]-修改后行政子公司[{}]-结果[{}]", !zsNormalUpdateOrderDTO.isBranchCompany(),
                orderDTO.getOrderWork().getDistributeWay(), orderDTO.getDbOrderDetail().getGridCompanyId(), orderDTO.getOrderDetail().getGridCompanyId(),
                headquartersDistributeBack);*/
        // 派单撤回
        if (orderBO.getDistributeBack() != null && orderBO.getDistributeBack().isStatusBool() && zsNormalUpdateOrderDTO.isVerifyDistributeBack()) {
//        if (normalDistributeBack || headquartersDistributeBack) {
            OrderDistributeBackDTO orderDistributeBackDTO = new OrderDistributeBackDTO();
            orderDistributeBackDTO.setWorkId(orderDTO.getWorkId());
            orderDistributeBackDTO.setOrderId(orderDTO.getOrderId());
            orderDistributeBackDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            orderDistributeBackDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            orderDistributeBackDTO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
            orderDistributeBackDTO.setOperatorRemark("修改订单，自动派单撤回，原因：" + orderBO.getDistributeBack().getData());
            orderDistributeBackDTO.setStatus(OrderStatusConsts.WORK_STATUS_ASSIGN);
            orderDistributeBackDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
            orderWorkDistributeBackBService.saveDistributeBack(orderDistributeBackDTO);
        }

        // 如果有预分配服务公司id，则存入redis
        if (NumberUtil.isNotNullOrZero(zsNormalUpdateOrderDTO.getPreManageCompanyId())){
            String redisKey = String.format(RedisKeyConsts.CHECK_MANAGE_COMPANY_KEY, zsNormalUpdateOrderDTO.getWorkId());
            String value = zsNormalUpdateOrderDTO.getPreManageCompanyId() + "-" + zsNormalUpdateOrderDTO.getPreManageCompanyName();
            redisManager.setex(redisKey, value, 7 * 24 * 60 * 60);
        }

        try {
            // 处理提前报价相关问题
            advanceQuoteModifyBService.processUpdateAdvanceQuote(orderDTO);
        } catch (Exception e) {
            logger.error("同步保存报价信息失败", e);
        }

        // 增加判断是否发送的到自动流转 默认发送 特殊情况设为否
        if (zsNormalUpdateOrderDTO.getAutoFlow()) {
            // 工单自动流转
            OrderWork orderWork = orderBO.getOrderWork();
            workFlowContextBService.asyncAutoFlowDelayMillis(orderWork.getOrderId(), orderWork.getWorkId(), 1500);
            //workFlowContextBService.asyncAutoFlow(orderWork.getOrderId(),orderWork.getWorkId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_INPUT)
    public OrderBO insertChannelOrder(ZsNormalNewOrderDTO zsNormalNewOrderDTO) throws OmsBaseException {
        tips4ParseProductOrCityFail(zsNormalNewOrderDTO);
        reviseOrder4Channel(zsNormalNewOrderDTO);

        // 保存订单
        OrderBO orderBO = doInsertOrder(zsNormalNewOrderDTO);

        OrderWork orderWork = orderBO.getOrderWork();
        Long orderId = orderWork.getOrderId();

        // 要客订单，更新用户为要客
        if (Objects.equals(zsNormalNewOrderDTO.getVvip(), GlobalConsts.YES)) {
            try {
                // 修改调用uuc接口  xiewenbing  2020-11-16
                com.zmn.common.dto2.ResponseDTO<Boolean> responseDTO = userModifyRemoteService.changeUserToVVipByUserId(orderWork.getUserId());
                logger.info("标记用户为要客：telephone=[{}, responseDTO=[{}]",
                        zsNormalNewOrderDTO.getTelephone(), JSON.toJSONString(responseDTO));
            } catch (Exception e) {
                logger.error("标记用户为要客失败：telephone=[{}], [{}]", zsNormalNewOrderDTO.getTelephone(), e.getMessage());
            }
        }

        // 维护线索中的啄木鸟订单ID
        if (zsNormalNewOrderDTO.getOrderClueId() != null) {
            try {
                facadeOrderClueDetailBService.saveZmnOrderIdByKey(zsNormalNewOrderDTO.getOrderClueId(), orderId);
            } catch (ChannelFacadeException e) {
                logger.error(e.getMessage(), e);
            }
        }

        return orderBO;
    }

    @Override
    public void updateAddress(ZsNormalAddressOrderDTO addressOrderDTO) throws OmsBaseException {
        if (NumberUtil.isNullOrZero(addressOrderDTO.getOrderId())) {
            throw new OmsBaseException("订单不能为空");
        }

        // 获取地址修改数据
        OrderDTO orderDTO = super.getUpdateAddressOrderDTO(addressOrderDTO);

        // 更新
        zsOrderBService.updateAddress(orderDTO);
    }

    @Override
    public void modifyAddress(UpdateAddressDIO updateAddressDIO) throws OmsBaseException {

        OrderWork dbOrderWork = orderWorkService.findMasterWorkDetail(updateAddressDIO.getOrderId(), updateAddressDIO.getWorkId(), updateAddressDIO.getMasterId());;
        // 校验工单是否属于该工程师
        if (Objects.isNull(dbOrderWork)) {
            throw new OmsBaseException("无效的工单");
        }

        // 不在进行中
        if (!Objects.equals(dbOrderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            throw new OmsBaseException("工单不在进行中");
        }

        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setDbOrderWork(dbOrderWork);

        orderDTO.setUpdateAddress(true);
        orderDTO.setOperatorId((long) updateAddressDIO.getMasterId());
        orderDTO.setOperator(updateAddressDIO.getMasterName());
        orderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
        orderDTO.setVersion(updateAddressDIO.getVersion());
        orderDTO.setAppPlat(updateAddressDIO.getAppPlat());
        orderDTO.setDisplayVersion(updateAddressDIO.getDisplayVersion());
        orderDTO.setAppPlat(updateAddressDIO.getAppPlat());

        orderDTO.setOrderId(updateAddressDIO.getOrderId());
        orderDTO.setWorkId(updateAddressDIO.getWorkId());

        OrderWork orderWork = new OrderWork();
        orderWork.setOrderId(updateAddressDIO.getOrderId());
        orderWork.setWorkId(updateAddressDIO.getWorkId());
        orderDTO.setOrderWork(orderWork);

        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setDetailId(updateAddressDIO.getOrderId());
        //orderDetail.setCountyId(updateAddressDIO.getCountyId());
        //orderDetail.setCountyName(updateAddressDIO.getCountyName());
        orderDetail.setStreetId(updateAddressDIO.getStreetId());
        orderDetail.setStreet(updateAddressDIO.getStreet());
        orderDetail.setAddress(updateAddressDIO.getAddress());
        orderDetail.setLatitude(updateAddressDIO.getNewLatitude());
        orderDetail.setLongitude(updateAddressDIO.getNewLongitude());


        com.zmn.common.dto2.ResponseDTO<AreaDRO> areaResponseDTO = areaListRemoteService.getAreaByLatAndLng(orderDetail.getLongitude(), orderDetail.getLatitude());
        com.zmn.base.common.data.common.dro.area.AreaDRO areaDRO = areaResponseDTO.getData();

        // 城市和经纬不匹配时，不处理
        if (areaDRO != null) {
            logger.info("通过经纬度获取城市数据，orderId={}, longitude={}, latitude={}, areaDRO={}", updateAddressDIO.getOrderId(), orderDetail.getLongitude(), orderDetail.getLatitude(), areaDRO);
            if (Objects.equals(dbOrderWork.getCityId(), areaDRO.getParentId())) {
                orderDetail.setCountyId(areaDRO.getAreaId());
                orderDetail.setCountyName(areaDRO.getName());
            }
        } else {
            logger.info("通过经纬度获取城市数据失败，orderId={}, longitude={}, latitude={}，result={}",
                    updateAddressDIO.getOrderId(), orderDetail.getLongitude(), orderDetail.getLatitude(), JSON.toJSONString(areaResponseDTO));
        }

        // 区县id不为空，取消名称为空，查出区县名称
        if (NumberUtil.isNotNullOrZero(orderDetail.getCountyId())
                && StringUtil.isBlank(orderDetail.getCountyName())) {
            com.zmn.common.dto2.ResponseDTO<AreaDRO> countyAreaResponse = areaListRemoteService.getById(orderDetail.getCountyId());
            logger.info("areaListRemoteService.getById({}) 出参{}", orderDetail.getCountyId(), JSON.toJSONString(countyAreaResponse));
            if (countyAreaResponse.getData() != null) {
                orderDetail.setCountyName(countyAreaResponse.getData().getName());
            }
        }

        orderDTO.setOrderDetail(orderDetail);
        //修改 masterWorking 地址
        if (Objects.nonNull(updateAddressDIO.getWorkId()) && Objects.nonNull(updateAddressDIO.getOrderId())){
            //仅仅为了获取countyName做拼接是否有必要 ？？
            OrderDetail orderDetailByKey = orderDetailService.findOrderDetailByKey(updateAddressDIO.getOrderId());
            MasterWorking masterWorking = new MasterWorking();
            masterWorking.setWorkId(updateAddressDIO.getWorkId());
            masterWorking.setAddress(String.format("%s%s%s", StringUtils.defaultString(orderDetailByKey.getCountyName()), StringUtils.defaultString(orderDetail.getStreet()), StringUtils.defaultString(orderDetail.getAddress())));
            masterWorking.setLatitude(updateAddressDIO.getNewLatitude());
            masterWorking.setLongitude(updateAddressDIO.getNewLongitude());
            masterWorkingService.updateMasterWorking(masterWorking);
        }


        // 更新
        zsOrderBService.updateAddress(orderDTO);
    }

    /**
     * 渠道创建订单无法自动确认工单提示语
     * 1、地址异常提示语：百度地址解析失败，请人工确认地址
     * 2、产品异常提示语：产品匹配失败，地址城市默认为总部重庆，请人工确认产品，并修改城市
     * @param zsNormalNewOrderDTO
     */
    private void tips4ParseProductOrCityFail(ZsNormalNewOrderDTO zsNormalNewOrderDTO) {
        boolean parseCityFail = false;
        if (zsNormalNewOrderDTO.getLatitude() == null || zsNormalNewOrderDTO.getLongitude() == null) {
            parseCityFail = true;
        }

        boolean parseProductFail = false;
        OrderProductDTO orderProduct = zsNormalNewOrderDTO.getOrderProductList().get(0);
        Integer productId = orderProduct.getShowProductId();
        if (NumberUtil.isNullOrZero(productId)) {
            productId = orderProduct.getProductId();
        }
        if (Objects.equals(OrderConsts.CHANNEL_DISABLED_PRODUCT_ID, productId)) {
            parseProductFail = true;
        }

        if (parseProductFail || parseCityFail) {
            StringJoiner logBuilder = new StringJoiner("；");

            if (parseCityFail) {
                logBuilder.add("百度地址解析失败，请人工确认地址");
            }
            if (parseProductFail) {
                logBuilder.add("产品匹配失败，请人工确认产品");
            }

            zsNormalNewOrderDTO.setOperatorLogRemark(logBuilder.toString());
        }
    }

    /**
     * 针对个别渠道的订单，需要做特殊调整和设置
     * @param newOrderDTO
     */
    private void reviseOrder4Channel(ZsNormalNewOrderDTO newOrderDTO) {
        Integer channelId = newOrderDTO.getChannelId();
        Integer servCategId = newOrderDTO.getServCategId();

        // 点评城市，已经纬度为准
        if (Objects.equals(channelId, OrderConsts.CHANNEL_ID_DIANPING)) {
            if (newOrderDTO.getLatitude() != null && newOrderDTO.getLongitude() != null) {
                com.zmn.common.dto2.ResponseDTO<AreaDRO> areaResponseDTO
                        = areaListRemoteService.getAreaByLatAndLng(newOrderDTO.getLongitude(), newOrderDTO.getLatitude());
                Optional.ofNullable(areaResponseDTO.getData())
                        .map(AreaDRO::getParentId)
                        .ifPresent(cityId -> newOrderDTO.setCityId(cityId));
            }
        }
        // 天猫无忧购订单，清洗单和管道疏通由啄木鸟平台服务，安装单由言而有信平台服务
        else if (Objects.equals(channelId, OrderConsts.CHANNEL_ID_TMALL_WYG)
                || Objects.equals(channelId, OrderConsts.CHANNEL_ID_TMALL_BUSINESS)
                || Objects.equals(channelId, OrderConsts.CHANNEL_ID_TMALL_PIPE)) {
            if (Objects.equals(channelId, OrderConsts.CHANNEL_ID_TMALL_WYG)
                    && (Objects.equals(servCategId, GlobalConsts.SERV_CATEG_CLEAN)
                    || Objects.equals(servCategId, GlobalConsts.SERV_CATEG_PIPE)) ) {
                // 勤鸽店的清洗和管道疏通单，不处理（默认规则为：服务平台与录单平台保持一致）
            }
            else {
                // 天猫订单，除了勤鸽店的清洗和管道疏通单，服务平台都指定为言而有信
                newOrderDTO.setPlatWork(GlobalConsts.PLAT_MARK_YEYX);
                newOrderDTO.setBizType(com.zmn.consts.GlobalConsts.BIZ_TYPE_F);
            }
        }
        // 京东服务+、天猫勤鸽保外渠道的订单，服务平台设置为啄木鸟  xiewenbing 2020-06-11
        else if (Objects.equals(channelId, JingdongConsts.CHANNEL_ID) ||
                Objects.equals(channelId, OrderConsts.CHANNEL_ID_TMALL_QINGE_BW)) {
            newOrderDTO.setPlatWork(GlobalConsts.PLAT_MARK_ZMN);
        }
        //
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_INPUT)
    public OrderBO insertOrder(ZsNormalNewOrderDTO zsNormalNewOrderDTO) throws OmsBaseException {
        zsNormalNewOrderDTO.setOperateTime(DateUtil.getNow());
        zsNormalNewOrderDTO.setReceiveEntranceId(NumberUtil.isNullOrZero(zsNormalNewOrderDTO.getReceiveEntranceId()) ? GateTypeConsts.GATE_PLAT_BACKSTAGE : zsNormalNewOrderDTO.getReceiveEntranceId());
        return doInsertOrder(zsNormalNewOrderDTO);
    }

    @Override
    public boolean isNoReimbursement(OrderWork orderWork) throws OmsBaseException {
        /*int reimburseStatus = orderWork.getPartReimburseStatus();
        if (!Objects.equals(reimburseStatus, OrderConsts.PART_REIMBURSE_STATUS_DOING)) {
            logger.info("[{}]判断不予报销false，非报销中", orderWork.getWorkId());
            return false;
        }*/

        if (Objects.equals(orderWork.getCompanyId(), CompanyConsts.ZMN_JXJ_COMPANY_ID)) {
            logger.info("[{}]判断不予报销false，家修匠公司", orderWork.getWorkId());
            return false;
        }

        if (!Objects.equals(orderWork.getManageCompanyType(), com.zmn.base.plat.engine.common.constant.CompanyConsts.COMPANY_TYPE_SERVICE_NOT_OCO)) {
            logger.info("[{}]判断不予报销false，不是非直营", orderWork.getWorkId());
            return false;
        }

        List<OrderPart> orderPartList = orderPartService.listByOrderId(orderWork.getOrderId());
        boolean isReimburse = orderPartList.stream().anyMatch(part -> Objects.equals(GlobalConsts.YES, part.getReimburse()));
        if (!isReimburse) {
            logger.info("[{}]判断不予报销false，未待报销配件", orderWork.getWorkId());
            return false;
        }
        boolean reimburseStatus = orderPartList.stream().anyMatch(part -> Objects.equals(OrderConsts.PART_REIMBURSE_STATUS_DOING, part.getReimburseStatus()));
        if (!reimburseStatus) {
            logger.info("[{}]判断不予报销false，非报销中", orderWork.getWorkId());
            return false;
        }

        int partAmount = orderPartList.stream()
                .filter(part -> Objects.equals(GlobalConsts.YES, part.getReimburse()))
                .mapToInt(part -> MathUtil.amountMultiplyNumber(part.getPrice(),
                        part.getNumber())).sum();

        com.zmn.common.dto2.ResponseDTO<List<ProductGroupDRO>> groupResponseDTO = productGroupForeignListRemoteService.listByGroupIdsAndStatus(Lists.newArrayList(orderWork.getServProductGroupId()), GlobalConsts.YES);
        logger.info("[{}]判断不予报销false，未待报销配件入参[{}],出参[{}]", orderWork.getWorkId(), orderWork.getServProductGroupId(), JSON.toJSONString(groupResponseDTO));
        if (!groupResponseDTO.isSuccess() || CollectionUtils.isEmpty(groupResponseDTO.getData())) {
            throw new OmsBaseException("无法获取订单产品组信息，请联系技术人员稍后重试");
        }
        ProductGroupDRO groupDRO = groupResponseDTO.getData().get(0);
        if (partAmount <= Optional.ofNullable(groupDRO.getReimbursement()).orElse(0)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 保存订单
     * @param zsNormalNewOrderDTO
     * @return
     * @throws OmsBaseException
     */
    private OrderBO  doInsertOrder(ZsNormalNewOrderDTO zsNormalNewOrderDTO) throws OmsBaseException {
        logger.debug("新单DTO:[{}]", JSON.toJSONString(zsNormalNewOrderDTO));
        if (CollectionUtils.isEmpty(zsNormalNewOrderDTO.getOrderProductList())) {
            throw new OmsBaseException("产品不能为空");
        }

        // 测试单处理
        if (isTestByTelephone(zsNormalNewOrderDTO)) {
            zsNormalNewOrderDTO.setTest(com.zmn.consts.GlobalConsts.YES);
        }

        //zsNormalNewOrderDTO.setOrderId(null);
        //zsNormalNewOrderDTO.setWorkId(null);
        zsNormalNewOrderDTO.setVvip(Objects.equals(GlobalConsts.YES, zsNormalNewOrderDTO.getVvip()) ? GlobalConsts.YES : GlobalConsts.NO);
        if (Objects.nonNull(zsNormalNewOrderDTO.getDutyTime()) && DateUtil.getNowTimestamp() > DateUtil.toTimestamp(zsNormalNewOrderDTO.getDutyTime())) {
            zsNormalNewOrderDTO.setDutyTime(null);
        }

        // 检查重复单
        //EsOrderWork duplicateOrder = null;
        /*if (!Objects.equals(zsNormalNewOrderDTO.getBizType(), com.zmn.consts.GlobalConsts.BIZ_TYPE_F)) {
            duplicateOrder = this.checkDuplicate(zsNormalNewOrderDTO);
        }*/
        // 产品处理
        orderBService.processBeforeOrderProduct(zsNormalNewOrderDTO.getOrderProductList().get(0));

        // 渠道，原渠道处理，返修单固定渠道
        if (Objects.equals(OrderConsts.ORDER_TYPE_REWORK, zsNormalNewOrderDTO.getType())) {
            OrderWork reworkOrderWork = orderWorkService.findOrderWorkByKey(zsNormalNewOrderDTO.getReworkId(), zsNormalNewOrderDTO.getReworkId());
            if(reworkOrderWork == null){
                throw new OmsBaseException("无效返修单号-返修单不存在");
            }
            zsNormalNewOrderDTO.setPlat(reworkOrderWork.getPlatWork());
            zsNormalNewOrderDTO.setPlatWork(reworkOrderWork.getPlatWork());
//            zsNormalNewOrderDTO.setChannelId(ChannelConsts.getReworkChannelId(reworkOrderWork.getPlatWork()));
//            zsNormalNewOrderDTO.setSourceChannelId(ChannelConsts.getReworkChannelId(reworkOrderWork.getPlatWork()));
            // 返修单 使用原单渠道
            zsNormalNewOrderDTO.setChannelId(reworkOrderWork.getChannelId());
            zsNormalNewOrderDTO.setSourceChannelId(reworkOrderWork.getSourceChannelId());
        }

        // 复制订单数据
        Order order = BeanMapper.map(zsNormalNewOrderDTO, Order.class);
        // 兼容处理，如果有老接口没有用新接口替换，也能正常下单
        if (Objects.isNull(order.getOrderId())){
            order.setOrderId(defaultKeyGenerator.generateKey().longValue());
        }
        order.setReceiveEntranceId(zsNormalNewOrderDTO.getReceiveEntranceId());
        OrderDetail orderDetail = BeanMapper.map(zsNormalNewOrderDTO, OrderDetail.class);
        OrderWork orderWork = BeanMapper.map(zsNormalNewOrderDTO, OrderWork.class);
        List<OrderProduct> orderProductList = Lists.newArrayListWithExpectedSize(zsNormalNewOrderDTO.getOrderProductList().size());
        zsNormalNewOrderDTO.getOrderProductList().forEach((item) -> {
            orderProductList.add(super.getProductInfo(item));
        });

        // 设置默认信息
        order.setPlat(Optional.ofNullable(zsNormalNewOrderDTO.getPlat()).orElse(GlobalConsts.PLAT_MARK_ZMN));
        order.setPlatWork(Optional.ofNullable(zsNormalNewOrderDTO.getPlatWork()).orElse(order.getPlat()));
        order.setSourceType(Optional.ofNullable(zsNormalNewOrderDTO.getSourceType()).orElse(OrderConsts.ORDER_SOURCE_TYPE_NORMAL));
        order.setBizType(zsNormalNewOrderDTO.getBizType() == null ? com.zmn.consts.GlobalConsts.BIZ_TYPE_C : zsNormalNewOrderDTO.getBizType());
        order.setResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
        order.setCreater(Optional.ofNullable(zsNormalNewOrderDTO.getOperator()).orElse(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM)));

        // 重复单信息
        /*if (Objects.nonNull(duplicateOrder)) {
            orderWork.setDuplicate(GlobalConsts.YES);
            orderWork.setDuplicateId(duplicateOrder.getId());
        }*/

        orderWork.setBizType(order.getBizType());
        orderWork.setOuterId(zsNormalNewOrderDTO.getOuterId());
        orderWork.setInputType(baseCodeService.getChannelInputType(GlobalConsts.PLAT_MARK_ZMN, orderWork.getChannelId(), Optional.ofNullable(zsNormalNewOrderDTO.getInputType()).orElse(OrderConsts.ORDER_INPUT_TYPE_MANUAL)));
        orderWork.setReceiverId(Optional.ofNullable(zsNormalNewOrderDTO.getOperatorId()).orElse((long)GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
        orderWork.setCreater(Optional.ofNullable(zsNormalNewOrderDTO.getOperator()).orElse(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM)));
        orderWork.setReceiveTime(DateUtil.getNow());
        orderWork.setReceiveEntranceId(zsNormalNewOrderDTO.getReceiveEntranceId());
        orderDetail.setGender(Optional.ofNullable(zsNormalNewOrderDTO.getGender()).orElse(GlobalDict.GENDER_NO));

        // 订单信息
        OrderDTO orderDTO = BeanMapper.map(zsNormalNewOrderDTO, OrderDTO.class);
        orderDTO.setOrder(order);
        orderDTO.setOrderDetail(orderDetail);
        orderDTO.setOrderProductList(orderProductList);
        orderDTO.setOrderWork(orderWork);
        orderDTO.setMosOrderDiscountList(zsNormalNewOrderDTO.getMosOrderDiscountList());

        // 处理提前报价数据 - 缓存
        this.processOrderFinalQuotation(orderDTO, zsNormalNewOrderDTO);

        // 订单活动
        if (NumberUtil.isNotNullOrZero(zsNormalNewOrderDTO.getActivityId())) {
            OrderActivity orderActivity = new OrderActivity();
            orderActivity.setActivityId(zsNormalNewOrderDTO.getActivityId());
            orderActivity.setCreater(Optional.ofNullable(zsNormalNewOrderDTO.getOperator()).orElse(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM)));
            orderActivity.setCreateTime(DateUtil.getNow());
            orderDTO.setOrderActivity(orderActivity);
        }

        // 扩展数据
        if (Objects.nonNull(zsNormalNewOrderDTO.getOrderExtend())) {
            orderDTO.setOrderExtend(BeanMapper.map(zsNormalNewOrderDTO.getOrderExtend(), OrderExtend.class));
        }
        if (Objects.nonNull(zsNormalNewOrderDTO.getCallId()) || Objects.nonNull(zsNormalNewOrderDTO.getOrderClueId())) {
            OrderExtend orderExtend = Optional.ofNullable(orderDTO.getOrderExtend()).orElse(new OrderExtend());
            orderExtend.setCallId(zsNormalNewOrderDTO.getCallId());
            orderExtend.setClueId(zsNormalNewOrderDTO.getOrderClueId());
            orderExtend.setBizClueId(zsNormalNewOrderDTO.getClueId());
            orderDTO.setOrderExtend(orderExtend);
        }

        // 保存前端传过来的计价器类型和服务项，用于比较，是否使用
        orderDTO.setOriginServItemType(zsNormalNewOrderDTO.getServItemType());
        orderDTO.setOriginOrderServiceItemList(zsNormalNewOrderDTO.getOrderServiceItemList());

        OrderProduct orderProduct = orderProductList.get(0);
        // 返修单，检查返修单号
        if (Objects.equals(OrderConsts.ORDER_TYPE_REWORK, zsNormalNewOrderDTO.getType())) {
            zsNormalNewOrderDTO.setOrderServiceItemList(Lists.newArrayList());
            CheckReworkOrderDTO checkReworkOrderDTO = new CheckReworkOrderDTO();
            checkReworkOrderDTO.setPlatWork(order.getPlatWork());
            checkReworkOrderDTO.setCityId(zsNormalNewOrderDTO.getCityId());
            checkReworkOrderDTO.setLatitude(zsNormalNewOrderDTO.getLatitude());
            checkReworkOrderDTO.setLongitude(zsNormalNewOrderDTO.getLongitude());
            checkReworkOrderDTO.setReworkId(zsNormalNewOrderDTO.getReworkId());
            checkReworkOrderDTO.setProductId(zsNormalNewOrderDTO.getOrderProductList().get(0).getProductId());
            checkReworkOrderDTO.setTelephone(zsNormalNewOrderDTO.getTelephone());
            checkReworkOrderDTO.setTelephone2(zsNormalNewOrderDTO.getTelephone2());
            checkReworkOrderDTO.setTelephone3(zsNormalNewOrderDTO.getTelephone3());
            checkReworkOrderDTO.setProductId(!NumberUtil.isNullOrZero(orderProduct.getShowProductId()) ? orderProduct.getShowProductId() : orderProduct.getProductId());
            checkReworkOrderDTO.setProductShowType(!NumberUtil.isNullOrZero(orderProduct.getShowProductId()) ? BaseProductConsts.EC_SHOW_TYPE : BaseProductConsts.ERP_SHOW_TYPE);
            super.checkReworkId(checkReworkOrderDTO);
        }

        // 订单处理
        orderBService.processOrder(orderDTO);
        orderWorkBService.processOrderWork(orderDTO);

        // 订单信息处理 newOrderDTO -> orderDTO
        orderProcessBService.processOrder(zsNormalNewOrderDTO, orderDTO);

        // 价格表id处理
        ProductTaraiffIdDTO productTaraiffIdDTO = ProductTaraiffIdDTO
                .builder()
                .channelId(zsNormalNewOrderDTO.getChannelId())
                .cityId(zsNormalNewOrderDTO.getCityId())
                .bizType(zsNormalNewOrderDTO.getBizType())
                .orderProductList(orderDTO.getOrderProductList())
                .build();
        servItemBService.processProductTaraiffId(productTaraiffIdDTO);

        // 计价器订单，保存计价器报价ID
        if (servItemBService.isQuotationType(orderDTO.getOrderWork().getServItemType()) && (zsNormalNewOrderDTO.getQuotationId() != null || CollectionUtil.isNotNullOrEmpty(zsNormalNewOrderDTO.getOrderServiceItemList()))) {
            OrderOperation orderOperation = new OrderOperation();
            orderOperation.setQuotationId(zsNormalNewOrderDTO.getOperatorId());
            orderOperation.setQuotationType(zsNormalNewOrderDTO.getQuotationType());
            orderOperation.setQuotationName(zsNormalNewOrderDTO.getOperator());
            orderOperation.setCreater(zsNormalNewOrderDTO.getOperator());

            Date currentTime = new Date();
            orderOperation.setQuotationTime(currentTime);
            orderOperation.setCreateTime(currentTime);
            orderDTO.setOrderOperation(orderOperation);
            logger.info("下单报价==》{}",orderOperation);
        }

        // 获取店铺
        orderDTO.setOrderShop(this.getOrderShop(zsNormalNewOrderDTO.getShopId(), zsNormalNewOrderDTO.getSceneId()));

        orderWork.setStatus(OrderStatusConsts.ORDER_STATUS_INPUT);

        // 保存订单
        OrderBO orderBO = zsOrderBService.insertOrder(orderDTO);

        // 计算原价
        //super.setOriginalAmount(orderDTO.getOrderWork(), null);

        // 计算工单金额
        CalcAddOrderAmountDIO calcAddOrderAmountDIO = new CalcAddOrderAmountDIO();
        calcAddOrderAmountDIO.setDiscountItemCodes(zsNormalNewOrderDTO.getDiscountItemCodes());
        calcAddOrderAmountDIO.setInvoker(zsNormalNewOrderDTO.getDiscountInvoker());
        calcAddOrderAmountDIO.setPromId(zsNormalNewOrderDTO.getPromId());
        calcAddOrderAmountDIO.setChannelDiscountAmount(zsNormalNewOrderDTO.getChannelDiscountAmount());
        calcAddOrderAmountDIO.setOrderAmountDIO(BeanMapper.map(orderWork, OrderAmountDIO.class));

        DiscountConditionParamsDIO discountConditionParamsDIO = BeanMapper.map(orderWork, DiscountConditionParamsDIO.class);
        discountConditionParamsDIO.setBrandId(orderDTO.getOrderProductList().get(0).getBrandId());
        discountConditionParamsDIO.setReceiveEntranceId(orderDTO.getReceiveEntranceId());

        calcAddOrderAmountDIO.setDiscountConditionParamsDIO(discountConditionParamsDIO);// 优惠的参数
        calcAddOrderAmountDIO.setUnusualDiscount(zsNormalNewOrderDTO.getUnusualDiscount());
        calcAddOrderAmountDIO.setTimesCoupCode(orderDTO.getTimesCoupCode());
        //是否是美团锁券下单
        calcAddOrderAmountDIO.setMeiTuanDiscount(this.isMeiTuanDiscount(orderDTO.getOrderExtend()));
        OrderAmountCalcBO orderAmountCalcBO = orderAmountCalcBService.calcOrderAmountAndDiscountAmount(calcAddOrderAmountDIO, zsNormalNewOrderDTO.getMosOrderDiscountList(), zsNormalNewOrderDTO.getOrderPayDiscountList());
        // 更新工单金额
        orderWorkAmountBService.updateAmountAndDiscount(orderAmountCalcBO, orderBO.getOrderWork());

        // 操作日志处理
        if (StringUtils.isNotBlank(orderDetail.getRemark())) {
            if (StringUtils.isNotBlank(zsNormalNewOrderDTO.getOperatorRemark())) {
                zsNormalNewOrderDTO.setOperatorRemark(String.format("订单备注：%s；%s", zsNormalNewOrderDTO.getOperatorRemark(), orderDetail.getRemark()));
            } else {
                zsNormalNewOrderDTO.setOperatorRemark(String.format("订单备注：%s", orderDetail.getRemark()));
            }
        }

        // 需要啄木鸟预付 一口价 & 先付 & 有服务项，预付超时取消 任务
        boolean finalPrice = Objects.equals(zsNormalNewOrderDTO.getFinalPrice(), GlobalConsts.YES) && Objects.equals(zsNormalNewOrderDTO.getPayType(), GlobalConsts.NO) && CollectionUtils.isNotEmpty(zsNormalNewOrderDTO.getOrderServiceItemList());
        boolean prepayAmount = Objects.equals(zsNormalNewOrderDTO.getPayType(), GlobalConsts.NO) && !NumberUtil.isNullOrZero(zsNormalNewOrderDTO.getPrepayAmount());
        if (finalPrice || prepayAmount) {
            addPrepayTimeoutCancelJob(orderBO.getOrderWork().getOrderId());
        }

        // 添加物流信息
        List<OrderPost> orderPostList = zsNormalNewOrderDTO.getOrderPostList();
        if (CollectionUtils.isNotEmpty(orderPostList)) {
            orderPostService.insertOrderPostList(order.getOrderId(), orderPostList);
            orderBO.setOrderPostList(orderPostList);
        }

        // 占用库存
//        Integer takeUpStockStatus = this.placeAnOrderTakeUpStock(zsNormalNewOrderDTO.getDistributeMasterDTO(), orderBO.getOrderWork());
        //添加下单派单信息
        this.addPlaceAnOrderDistribute(zsNormalNewOrderDTO.getDistributeMasterDTO(), orderBO.getOrderWork(), GlobalConsts.NO);

        // 一口价扩展数据
        this.addFinalPriceOrderExt(orderBO.getOrderWork(), zsNormalNewOrderDTO.getFinalPriceNewOrderExtDTO());

        // 外部店铺信息
        this.addOrderExternalShop(zsNormalNewOrderDTO.getExternalShopInfo(), orderBO.getOrderWork(), zsNormalNewOrderDTO.getOperator());

        // 报价数据
        this.addFinalPriceQuotation(orderBO, orderDTO, zsNormalNewOrderDTO, orderAmountCalcBO);

        // 返回处理
        zsNormalNewOrderDTO.setOrderId(orderBO.getOrderWork().getOrderId());
        zsNormalNewOrderDTO.setWorkId(orderBO.getOrderWork().getWorkId());

        // 如果有预分配服务公司id，则存入redis
        if (NumberUtil.isNotNullOrZero(zsNormalNewOrderDTO.getPreManageCompanyId())){
            String redisKey = String.format(RedisKeyConsts.CHECK_MANAGE_COMPANY_KEY, zsNormalNewOrderDTO.getWorkId());
            String value = zsNormalNewOrderDTO.getPreManageCompanyId() + "-" + zsNormalNewOrderDTO.getPreManageCompanyName();
            redisManager.setex(redisKey, value, 7 * 24 * 60 * 60);
        }

        this.addOrderEventLog(orderBO, zsNormalNewOrderDTO);

        // 返修单 设置责任工程师
        this.addOrderLiableMaster(zsNormalNewOrderDTO);
        return orderBO;
    }

    /**
     * 是否美团锁券下单优惠
     * @param orderExtend
     * @return 1否，2是
     */
    private Integer isMeiTuanDiscount(OrderExtend orderExtend) {

        if (Objects.isNull(orderExtend)) {
            return GlobalConsts.NO;
        }

        String outerData = orderExtend.getOuterData();
        if (StringUtil.isBlank(outerData)) {
            return GlobalConsts.NO;
        }

        JSONObject jsonObject = JSONObject.parseObject(orderExtend.getOuterData());
        if (Objects.isNull(jsonObject)) {
            return GlobalConsts.NO;
        }

        // 如果不是美团优惠直接返回
        String openShopId = jsonObject.getString("open_shop_uuid");
        if (StringUtil.isNotBlank(openShopId)) {
            return GlobalConsts.YES;
        }
        return GlobalConsts.NO;
    }

    /**
     * 设置返修单责任工程师
     * @param zsNormalNewOrderDTO
     * @author huangchao
     */
    private void addOrderLiableMaster(ZsNormalNewOrderDTO zsNormalNewOrderDTO) {
        if (Objects.equals(OrderConsts.ORDER_TYPE_REWORK, zsNormalNewOrderDTO.getType())) {
            // 查询完成后的新一次返修单
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .filter(QueryBuilders.rangeQuery("status").gte(OrderStatusConsts.WORK_STATUS_COMPLETE))
                    .filter(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_REWORK))
                    .filter(QueryBuilders.termQuery("reworkId", zsNormalNewOrderDTO.getReworkId()));
            NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
            searchQuery.setPageable(PageRequest.of(0, 1, Sort.by(Sort.Order.desc("receiveTime"))));
            searchQuery.addSourceFilter(new FetchSourceFilterBuilder().withIncludes("orderId", "masterId", "masterName").build());

            List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(searchQuery);
            ChangeLiableMasterDTO changeLiableMasterDTO = new ChangeLiableMasterDTO();
            if (com.zmn.common.utils.collection.CollectionUtil.isNotNullOrEmpty(page)) {
                EsOrderWork esOrderWork = page.get(0);
                changeLiableMasterDTO.setOrderId(zsNormalNewOrderDTO.getOrderId());
                changeLiableMasterDTO.setLiableMasterId(esOrderWork.getMasterId());
                changeLiableMasterDTO.setLiableMasterName(esOrderWork.getMasterName());
                changeLiableMasterDTO.setCancelLiableMasterId(esOrderWork.getMasterId());
                changeLiableMasterDTO.setCancelLiableMasterName(esOrderWork.getMasterName());
            }else {
                OrderWork liableWork = orderWorkService.findOrderWorkByKey(zsNormalNewOrderDTO.getReworkId(), zsNormalNewOrderDTO.getReworkId());
                changeLiableMasterDTO.setOrderId(zsNormalNewOrderDTO.getOrderId());
                changeLiableMasterDTO.setLiableMasterId(liableWork.getMasterId());
                changeLiableMasterDTO.setLiableMasterName(liableWork.getMasterName());
                changeLiableMasterDTO.setCancelLiableMasterId(liableWork.getMasterId());
                changeLiableMasterDTO.setCancelLiableMasterName(liableWork.getMasterName());
            }
            changeLiableMasterDTO.setOperator(Optional.ofNullable(zsNormalNewOrderDTO.getOperator()).orElse(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM)));
            changeLiableMasterDTO.setOperateTime(DateUtil.getNow());
            orderChangeRecordService.updateCancelLiableAndLiableMasterRecord(changeLiableMasterDTO);
        }
    }

    /**
     * 新增订单埋点
     *
     * @param orderBO
     */
    private void addOrderEventLog(OrderBO orderBO, ZsNormalNewOrderDTO zsNormalNewOrderDTO) {
        try {
            // 如果是运营后台录单和api录单则新增订单埋点
            boolean isOrderLog = Objects.equals(zsNormalNewOrderDTO.getReceiveEntranceId(), GateTypeConsts.GATE_PLAT_BACKSTAGE)
                    || Objects.equals(zsNormalNewOrderDTO.getReceiveEntranceId(), GateTypeConsts.GATE_API_NORM)
                    || Objects.equals(zsNormalNewOrderDTO.getReceiveEntranceId(), GateTypeConsts.GATE_API_TMALL)
                    || Objects.equals(zsNormalNewOrderDTO.getReceiveEntranceId(), GateTypeConsts.GATE_API_CUSTOM_MADE)
                    || Objects.equals(zsNormalNewOrderDTO.getReceiveEntranceId(), GateTypeConsts.GATE_WECHAT_H5_OLD);

            if (!isOrderLog){
                return;
            }

            String site = "zmn-oms-admin";
            if (!Objects.equals(zsNormalNewOrderDTO.getReceiveEntranceId(), GateTypeConsts.GATE_PLAT_BACKSTAGE)){
                site = "zmn-oms-api";
            }

            OrderWork orderWork = orderBO.getOrderWork();
            OrderDetail orderDetail = orderBO.getOrderDetail();
            List<OrderProduct> orderProductList = orderBO.getOrderProductList();
            OrderProduct orderProduct = orderProductList.get(0);

            AddOrderEventLogItem eventLogItem = new AddOrderEventLogItem();
            eventLogItem.setBizId(String.valueOf(orderWork.getOrderId()));
            eventLogItem.setOrderId(String.valueOf(orderWork.getOrderId()));
            if (NumberUtil.isNotNullOrZero(orderProduct.getProductId())) {
                eventLogItem.setProductId(String.valueOf(orderProduct.getProductId()));
                eventLogItem.setProductName(orderProduct.getProductName());
            } else {
                eventLogItem.setProductId(String.valueOf(orderProduct.getShowProductId()));
                eventLogItem.setProductName(orderProduct.getShowProductName());
            }
            eventLogItem.setChannelId(String.valueOf(orderWork.getChannelId()));
            eventLogItem.setOrderChannelId(String.valueOf(orderWork.getChannelId()));
            eventLogItem.setSourceChannelId(String.valueOf(orderWork.getSourceChannelId()));
            eventLogItem.setLng(Objects.isNull(orderDetail.getLongitude()) ? "" : String.valueOf(orderDetail.getLongitude()));
            eventLogItem.setLat(Objects.isNull(orderDetail.getLatitude()) ? "" : String.valueOf(orderDetail.getLatitude()));
            eventLogItem.setSite(site);

            UserLogItem staffUserLogItem = new UserLogItem();
            staffUserLogItem.setUserType(UserType.INDIVIDUAL_USER);
            staffUserLogItem.setUserId(String.valueOf(orderWork.getUserId()));
            staffUserLogItem.setUserName(orderDetail.getUserName());

            DeviceLogItem deviceLogItem = new DeviceLogItem();
            deviceLogItem.setIp(zsNormalNewOrderDTO.getIp());
            UserAgent userAgent = UserAgent.parseUserAgentString(zsNormalNewOrderDTO.getUserAgent());
            if (Objects.nonNull(userAgent)) {
                deviceLogItem.setBrowser(userAgent.getBrowser().getName());
                deviceLogItem.setOs(userAgent.getOperatingSystem().getName());
            }

            EntryLogItem entryLogItem = new EntryLogItem();
            entryLogItem.setEntryType(String.valueOf(GateTypeConsts.GATE_TYPE_PLAT));
            entryLogItem.setEntry(String.valueOf(GateTypeConsts.GATE_PLAT_BACKSTAGE));

            AddUserOperationLogRequest<AddOrderEventLogItem> request = new AddUserOperationLogRequest<>();
            request.setUser(staffUserLogItem);
            request.setEntry(entryLogItem);
            request.setDevice(deviceLogItem);
            request.setEvent(eventLogItem);
            request.setClientName(site);

            logClient.addAddOrderEventLog(request);
        } catch (Exception e) {
            logger.error("addLookOrderEventLog error：", e);
        }
    }

    /**
     * 添加超时取消任务
     *
     * @param orderId
     */
    private void addPrepayTimeoutCancelJob(Long orderId) {
        Job job = new Job();
        job.setTaskId(TaskConsts.TASK_ID_PREPAY_TIMEOUT_CANCEL + ":" + orderId);
        job.setParam("orderId", orderId.toString());
        job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_PREPAY_TIMEOUT_CANCEL);
        Date date = DateUtil.addMinute(DateUtil.getNow(), OrderConsts.ORDER_PREPAY_TIMEOUT_CANCEL_MINUTES);
        taskManager.submitTask(job, -1, DateUtil.dateFormatToString(date, DateUtil.FORMAT_DEFAULT));
    }

    /**
     * 获取店铺信息
     *
     * @param shopId
     * @return
     */
    private OrderShop getOrderShop(Integer shopId, String sceneId) {
        if (NumberUtil.isNullOrZero(shopId)) {
            return null;
        }
        OrderShop orderShop = new OrderShop();
        orderShop.setShopId(shopId);
        orderShop.setSceneId(sceneId);
        // 取店铺信息
        ResponseDTO<ShopDRO> shop = shopRemoteService.getShop(ShopDIO.builder().shopId(shopId).build());
        if (shop.getStatusBool() && shop.getData() != null) {
            orderShop.setShopType(shop.getData().getType());
            orderShop.setShopName(StringUtils.defaultString(shop.getData().getShopName()));
        }
        return orderShop;
    }

    private void addPlaceAnOrderDistribute(NewOrderDistributeMasterDTO distributeMasterDTO, OrderWork orderWork, Integer takeUpStockStatus) {
        logger.info("placeAnOrderDistribute orderId={}", orderWork.getOrderId());
        if (Objects.isNull(distributeMasterDTO)) {
            return;
        }
        if (NumberUtil.isNullOrZero(distributeMasterDTO.getDistributeMasterId())) {
            return;
        }

        OrderPreDistributeRecord orderPreDistributeRecord = new OrderPreDistributeRecord();
        orderPreDistributeRecord.setMasterId(distributeMasterDTO.getDistributeMasterId());
        orderPreDistributeRecord.setOrderId(orderWork.getOrderId());
        orderPreDistributeRecord.setWorkId(orderWork.getWorkId());
        orderPreDistributeRecord.setPreDistributeSource(OrderDistributeConsts.PRE_DISTRIBUTE_SOURCE_PLACE_AN_ORDER);
        orderPreDistributeRecord.setPreDistributeStatus(takeUpStockStatus);
        preDistributeRecordService.insertOrderPreDistributeRecord(orderPreDistributeRecord);

        PlaceAnOrderPreDistribute placeAnOrderPreDistribute = new PlaceAnOrderPreDistribute();
        placeAnOrderPreDistribute.setWorkId(orderWork.getWorkId());
        placeAnOrderPreDistribute.setOrderId(orderWork.getOrderId());
        placeAnOrderPreDistribute.setPreDistributeId(orderPreDistributeRecord.getPreDistributeId());
        placeAnOrderPreDistribute.setDistributeVO(JSON.parseObject(distributeMasterDTO.getDistributeJsonStr(), DistributeVO.class));
        zsDistributeWorkBService.addPlaceAnOrderDistribute(placeAnOrderPreDistribute);
    }

    private void addOrderExternalShop(NewOrderExternalShopDTO externalShopDTO, OrderWork orderWork,String operator) {
        if (Objects.isNull(externalShopDTO)) {
            return;
        }

        OrderExternalShop orderExternalShop = new OrderExternalShop();
        orderExternalShop.setOrderId(orderWork.getOrderId());
        orderExternalShop.setWorkId(orderWork.getWorkId());
        orderExternalShop.setExternalShopId(externalShopDTO.getExternalShopId());
        orderExternalShop.setInternalShopId(Objects.isNull(externalShopDTO.getInternalShopId()) ? null : externalShopDTO.getInternalShopId().longValue());
        orderExternalShop.setInternalShopName(externalShopDTO.getInternalShopName());
        orderExternalShop.setInternalBranchShopName(externalShopDTO.getInternalBranchShopName());
        orderExternalShop.setCreater(operator);
        orderExternalShopService.insert(orderExternalShop);
    }

    /**
     * 下单占用库存
     * @param distributeMasterDTO
     * @param orderWork
     * @return 占用成功/失败
     */

    private Integer placeAnOrderTakeUpStock(NewOrderDistributeMasterDTO distributeMasterDTO, OrderWork orderWork) {
        logger.info("placeAnOrderTakeUpStock orderId={}", orderWork.getOrderId());
        if (Objects.isNull(distributeMasterDTO)) {
            return GlobalConsts.NO;
        }
        if (NumberUtil.isNullOrZero(distributeMasterDTO.getDistributeMasterId())) {
            return GlobalConsts.NO;
        }
        LockStockDTO lockStockDTO = LockStockDTO
                .builder()
                .isDistributeLockStock(true)
                .masterId(distributeMasterDTO.getDistributeMasterId())
                .build();
        try {
            orderStockBService.takeUpStock(lockStockDTO, orderWork);
        } catch (Exception e) {
            logger.error("orderStockBService.takeUpStock error={}", e.getMessage());
            return GlobalConsts.NO;
        }

        boolean checkExitOrder = false;
        try {
            checkExitOrder = orderStockBService.checkExitOrder(orderWork.getWorkId(), distributeMasterDTO.getDistributeMasterId());
        } catch (Exception e) {
            logger.error("orderStockBService.checkExitOrder error={}", e.getMessage());
            return GlobalConsts.NO;
        }
        if (checkExitOrder) {
            ReleaseStockDTO releaseStockDTO = ReleaseStockDTO
                    .builder()
                    .cityId(orderWork.getCityId())
                    .orderId(orderWork.getOrderId())
                    .workId(orderWork.getWorkId())
                    .masterId(distributeMasterDTO.getDistributeMasterId())
                    .build();
            String json = JSON.toJSONString(releaseStockDTO);
            String key = StringUtil.getRandomsString(32);
            long time = System.currentTimeMillis() + 1000 * 60 * 10;
            zmnMQSender.sendWithStartDeliverTime(MqTopicConsts.ZMN_TOPIC_OMS, OmsMqTagConsts.ORDER_MASTER_RELEASE_STOCK, key, json, time);
        }else {
            return GlobalConsts.NO;
        }
        return GlobalConsts.YES;
    }

    /**
     * 是否是测试单
     *
     * @param newOrderDTO
     * @return
     */
    private boolean isTestByTelephone(ZsNormalNewOrderDTO newOrderDTO) {
        if (StringUtil.isNotBlank(newOrderDTO.getTelephone()) && ORDER_AUTO_MARK_TEST_TELEPHONE.contains(newOrderDTO.getTelephone())) {
            return true;
        }
        if (StringUtil.isNotBlank(newOrderDTO.getTelephone2()) && ORDER_AUTO_MARK_TEST_TELEPHONE.contains(newOrderDTO.getTelephone2())) {
            return true;
        }
        return StringUtil.isNotBlank(newOrderDTO.getTelephone3()) && ORDER_AUTO_MARK_TEST_TELEPHONE.contains(newOrderDTO.getTelephone3());
    }

    private void addFinalPriceOrderExt(OrderWork orderWork, FinalPriceNewOrderExtDTO finalPriceNewOrderExtDTO) {
        if (!Objects.equals(orderWork.getFinalPrice(), GlobalConsts.YES)) {
            return;
        }

        if (Objects.isNull(finalPriceNewOrderExtDTO)) {
            return;
        }

        OrderFinalPrice findPriceOrderExt = new OrderFinalPrice();
        findPriceOrderExt.setOrderId(orderWork.getOrderId());
        findPriceOrderExt.setWorkId(orderWork.getWorkId());
        findPriceOrderExt.setPayType(finalPriceNewOrderExtDTO.getPayType());
        findPriceOrderExt.setItemTypeId(finalPriceNewOrderExtDTO.getItemTypeId());
        findPriceOrderExt.setItemTypeName(finalPriceNewOrderExtDTO.getItemTypeName());
        findPriceOrderExt.setCreater(orderWork.getCreater());
        orderFinalPriceService.insertOrderFindPrice(findPriceOrderExt);
    }

    private void addFinalPriceQuotation(OrderBO orderBO, OrderDTO orderDTO, ZsNormalNewOrderDTO zsNormalNewOrderDTO, OrderAmountCalcBO amountCalcBO) {

        OrderWork orderWork = orderDTO.getOrderWork();
        OrderProduct orderProduct = orderDTO.getOrderProductList().get(0);

        OrderFinalPriceQuotation quotation = super.getOrderFinalPriceQuotation(orderDTO, zsNormalNewOrderDTO, amountCalcBO);
        if (Objects.isNull(quotation)) {
            return;
        }

        // 保存提前报价信息
        orderFinalPriceQuotationBService.saveOrderFinalPriceQuotation(orderDTO, quotation, orderWork, orderProduct);

        orderBO.setQuotationList(Lists.newArrayList(quotation));
    }

    private void processOrderFinalQuotation(OrderDTO orderDTO, ZsNormalNewOrderDTO zsNormalNewOrderDTO) {
        if(Objects.isNull(zsNormalNewOrderDTO) || CollectionUtil.isNullOrEmpty(zsNormalNewOrderDTO.getOrderProductList())) {
            return;
        }

        if (Objects.isNull(zsNormalNewOrderDTO.getOrderProductList().get(0).getAdvanceQuote())) {
            return;
        }

        NewOrderAdvanceQuoteDTO quoteDTO = zsNormalNewOrderDTO.getOrderProductList().get(0).getAdvanceQuote();
        OrderFinalPriceQuotation orderFinalPriceQuotation = new OrderFinalPriceQuotation();
        orderFinalPriceQuotation.setQuotationType(quoteDTO.getQuoteType());
        orderFinalPriceQuotation.setServItemId(quoteDTO.getItemId());
        orderFinalPriceQuotation.setPhenId(quoteDTO.getPhenId());
        orderFinalPriceQuotation.setPhenName(quoteDTO.getPhenName());

        orderDTO.setOrderFinalPriceQuotation(orderFinalPriceQuotation);

    }
}
